package pl.edu.agh.gronoMining.frequentSubgraphFinder.frequentSearcher.subgraph.impl;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

import pl.edu.agh.gronoMining.frequentSubgraphFinder.frequentSearcher.subgraph.DFSCode;
import pl.edu.agh.gronoMining.frequentSubgraphFinder.graph.Edge;
import pl.edu.agh.gronoMining.frequentSubgraphFinder.graph.Graph;
import pl.edu.agh.gronoMining.frequentSubgraphFinder.graph.GraphException;
import pl.edu.agh.gronoMining.frequentSubgraphFinder.graph.Node;
import pl.edu.agh.gronoMining.frequentSubgraphFinder.graph.simpleGraph.SimpleEdge;
import pl.edu.agh.gronoMining.frequentSubgraphFinder.graph.simpleGraph.SimpleGraph;
import pl.edu.agh.gronoMining.frequentSubgraphFinder.graph.simpleGraph.SimpleNode;

public class DFSCodeImpl implements DFSCode {

	// (id1, id2, typ1, typ2, label1, label2, edgeLabel)
	
	private int[] id1;
	private int[] id2;
	private int[] type1;
	private int[] type2;
	private int[] label1;
	private int[] label2;
	private int[] edgeLabel;
	
	private int index = 0;
	private int idIndex = 0;
	
	private Map<Integer, Integer> outerToInnterMap = null;
	
	public DFSCodeImpl(int edgesNumber) {
		this.id1 = new int[edgesNumber];
		this.id2 = new int[edgesNumber];
		this.type1 = new int[edgesNumber];
		this.type2 = new int[edgesNumber];
		this.label1 = new int[edgesNumber];
		this.label2 = new int[edgesNumber];
		this.edgeLabel = new int[edgesNumber];
	}
	
	public void addEdge(int id1, int id2, int type1, int type2, int label1, int label2, int edgeLabel) {
		this.id1[index] = id1;
		this.id2[index] = id2;
		this.type1[index] = type1;
		this.type2[index] = type2;
		this.label1[index] = label1;
		this.label2[index] = label2;
		this.edgeLabel[index] = edgeLabel;
		this.index++;
	}
	
	public void addEdge(Edge edge) {
		Integer id1Int = outerToInnterMap.get(edge.getNodeA().getId());
		if (id1Int == null) {
			id1Int = this.idIndex;
			this.outerToInnterMap.put(edge.getNodeA().getId(), this.idIndex);
			this.idIndex++;
		}
		Integer id2Int = outerToInnterMap.get(edge.getNodeB().getId());
		if (id2Int == null) {
			id2Int = this.idIndex;
			this.outerToInnterMap.put(edge.getNodeB().getId(), this.idIndex);
			this.idIndex++;
		}
		this.id1[index] = id1Int;
		this.id2[index] = id2Int;
		this.type1[index] = edge.getNodeA().getType();
		this.type2[index] = edge.getNodeB().getType();
		this.label1[index] = edge.getNodeA().getLabel();
		this.label2[index] = edge.getNodeB().getLabel();
		this.edgeLabel[index] = edge.getLabel();
		this.index++;
	}
	
	public void createOuterToInnterMap() {
		outerToInnterMap = new HashMap<Integer, Integer>();
		this.idIndex = 0;
	}
	
	public void removeOuterToInnterMap() {
		outerToInnterMap = null;
	}
	
	public int[] getId1Array() {
		return id1;
	}
	
	public int[] getId2Array() {
		return id2;
	}
	
	public int[] getType1Array() {
		return type1;
	}
	
	public int[] getType2Array() {
		return type2;
	}
	
	public int[] getLabel1Array() {
		return label1;
	}
	
	public int[] getLabel2Array() {
		return label2;
	}
	
	public int[] getEdgeLabelArray() {
		return edgeLabel;
	}
	
	public Graph getAsGraph() {
		Graph g = new SimpleGraph();
		
		try {
			for (int i=0; i<id1.length; i++) {
				
				if (g.getNodeById(id1[i]) == null) {
					Node node = new SimpleNode(id1[i], label1[i], type1[i]);
					g.addNode(node);
				}
				
				if (g.getNodeById(id2[i]) == null) {
					Node node = new SimpleNode(id2[i], label2[i], type2[i]);
					g.addNode(node);
				}
				
			}
			
			for (int i=0; i<id1.length; i++) {
				Node node1 = g.getNodeById(id1[i]);
				Node node2 = g.getNodeById(id2[i]);
				Edge edge = new SimpleEdge(edgeLabel[i], node1, node2);
				edge.checkIntegraty();
			}
		} catch (GraphException e) {
			e.printStackTrace();
		}

		return g;
	}
	
	public boolean equals(Object o) {
		DFSCode dfs = (DFSCode) o;
		
		if (dfs.getId1Array().length != id1.length)
			return false;
		
		if (! Arrays.equals(id1, dfs.getId1Array()))
			return false;
		if (! Arrays.equals(id2, dfs.getId2Array()))
			return false;
		if (! Arrays.equals(type1, dfs.getType1Array()))
			return false;
		if (! Arrays.equals(type2, dfs.getType2Array()))
			return false;
		if (! Arrays.equals(label1, dfs.getLabel1Array()))
			return false;
		if (! Arrays.equals(label2, dfs.getLabel2Array()))
			return false;
		if (! Arrays.equals(edgeLabel, dfs.getEdgeLabelArray()))
			return false;
		
		return true;
	}
	
	public int hashCode() {
		int code = 0;
		for (int i=0; i<id1.length; i++) {
			code += new Integer(label1[i]).hashCode();
			code += new Integer(label2[i]).hashCode();
		}
		return code;
	}
	
	public String toString() {
		String text = "";
		for (int i=0; i<id1.length; i++) {
			text += "("+id1[i]+", "+type1[i]+", "+label1[i]+" -> "+id2[i]+", "+type2[i]+", "+label2[i]+") - "+edgeLabel[i]+"\n";
		}
		return text;
	}
	
}
